package com.xjoyt.pay.abstracts;

import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.criteria.Predicate;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;

import com.xjoyt.pay.annotations.PredicateCommand;
import com.xjoyt.pay.constants.DateConstant;
import com.xjoyt.pay.dto.PageParam;

public abstract class AbstractDao {

	protected static final Logger logger = LoggerFactory.getLogger(AbstractDao.class);

	@Autowired
	protected EntityManager entityManager;

	protected Pageable getPageable(PageParam<?> param) {
		if (StringUtils.isBlank(param.sort)) {
			return new PageRequest(param.page - 1, param.rows);
		}
		Sort pageSort = new Sort(StringUtils.isBlank(param.order) || "DESC".equals(param.order.toUpperCase())
				? Direction.DESC : Direction.ASC, param.sort);
		Pageable pageable = new PageRequest(param.page - 1, param.rows, pageSort);
		return pageable;
	}

	protected Pageable getFirstPageable() {
		Pageable pageable = new PageRequest(0, 1);
		return pageable;
	}

	protected Date toStartDate(Date date) {
		try {
			return DateUtils.parseDate(DateFormatUtils.format(date, DateConstant.DATE_FORMAT_PATTERN),
					DateConstant.DATE_PARSE_PATTERNS);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	protected Date toEndDate(Date date) {
		try {
			return DateUtils.parseDate(DateFormatUtils.format(date, DateConstant.DATE_FORMAT_PATTERN) + " 23:59:59",
					DateConstant.DATE_PARSE_PATTERNS);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	protected <T> Specification<T> getSpecification(Class<?> cls, Object param) {
		Specification<T> spec = (root, query, cb) -> {
			List<Predicate> list = new ArrayList<>();
			try {
				Object instance = cls.newInstance();
				for (Method method : cls.getMethods()) {
					if (!method.isAnnotationPresent(PredicateCommand.class))
						continue;
					Object invoke = method.invoke(instance, param, root, query, cb);
					if (invoke == null || !(invoke instanceof List))
						continue;

					List<?> predicateList = (List<?>) invoke;
					for (Object obj : predicateList) {
						if (obj == null || !(obj instanceof Predicate))
							continue;
						list.add((Predicate) obj);
					}
				}
			} catch (Exception e) {
				logger.error("获取Specification异常", e);
				e.printStackTrace();
			}

			if (CollectionUtils.isNotEmpty(list))
				query.where(cb.and(list.toArray(new Predicate[list.size()])));

			return null;
		};
		return spec;
	}
}
